
#include "Shape.h"

#include <cmath>

/*!
    \namespace Foo
    \brief The namespace of this sample codes.

    Use it so that the global namespace won't be poluted.
*/

namespace Foo {

    /*!
        \class Shape
        \brief The abstract class of a geometric shape.
    */

    /*!
        \enum Shape::Type
        \brief This enum is an identifier of the shape type of derived classes.

        \var Shape::Rectangle
        \brief Rectangle shape

        \var Shape::Triangle
        \brief Triangle shape
    */

    /*!
        Constructs a Shape instance.
    */
    Shape::Shape(Type type) : t(type) {
    }

    /*!
        The destructor is virtual.
    */
    Shape::~Shape() {
    }

    /*!
        Returns the type of the shape.
    */
    Shape::Type Shape::type() const {
        return static_cast<Type>(t);
    }

    /*!
        \fn int Shape::area() const
        \overload

        Returns the area of the shape.
    */

    /*!
        \class Rectangle
        \brief The implementation of rectangle to class Shape.
    */

    /*!
        Constructs a Rectangle instance with null parameters.
    */
    Rectangle::Rectangle() : Rectangle(0, 0) {
    }

    /*!
        Constructs a Rectangle with given width and height.
    */
    Rectangle::Rectangle(int w, int h) : Shape(Shape::Rectangle), w(w), h(h) {
    }

    /*!
        Returns the width.
    */
    int Rectangle::width() const {
        return w;
    }

    /*!
        Sets the width.
    */
    void Rectangle::setWidth(int width) {
        w = width;
    }

    /*!
        Returns the height.
    */
    int Rectangle::height() const {
        return h;
    }

    /*!
        Returns the area of the rect, normally it's the production of width and height.
    */
    int Rectangle::area() const {
        return w * h;
    }

    /*!
        Sets the height.
    */
    void Rectangle::setHeight(int height) {
        h = height;
    }

    /*!
        \class Triangle
        \brief The implementation of triangle to class Shape.
    */

    /*!
        Constructs a Triangle instance with null parameters.
    */
    Triangle::Triangle() : Triangle(0, 0, 0) {
    }

    /*!
        Constructs a Rectangle with given side sizes.
    */
    Triangle::Triangle(int a, int b, int c) : Shape(Shape::Triangle), a(a), b(b), c(c) {
    }

    /*!
        Returns \c true if the triangle has a valid side sizes;
        otherwise returns \c false.
    */
    bool Triangle::isValid() const {
        return (a > 0) && (b > 0) && (c > 0) && (a + b > c) && (a + c > b) && (b + c > a);
    }

    /*!
        Returns a list of side sizes.
    */
    std::vector<int> Triangle::sizes() const {
        return {a, b, c};
    }

    /*!
        Sets the side sizes.
    */
    void Triangle::setSizes(int a, int b, int c) {
        this->a = a;
        this->b = b;
        this->c = c;
    }

    /*!
        Returns the area of the triangle, using Heron's formula.

        \warning Don't call this function if the triangle is invalid.
    */
    int Triangle::area() const {
        if (!isValid())
            return  0;
        auto p = double(a + b + c) / 2;
        return std::sqrt(p * (p - a) * (p - b) * (p -c));
    }

}